import datetime
import json
import logging
import time

import requests
from sqlalchemy import or_, text, func, distinct, and_

from app.commons.config import async_exec
from app.commons.db import db
from app.commons.redis_session import redis_con
from app.models.buff_stock.buyer_stock import BuyerStockInfo
from app.models.buff_stock.rent import RentInfo
from app.models.buff_stock.stock import StockInfo


def get_total_info(username):
    # UpdateCurrentPrice()
    result = {
        "total_item": 0,
        "total_buy_price": 0,
        "total_current_price": 0,
        "total_rent": 0,
        "rent_interest": 0,
        "total_interest": 0,
        "last_7d_rent": 0,
        "last_14d_rent": 0,
        "last_30d_rent": 0
    }
    with_buyer_stock_tab = BuyerStockInfo.query.with_entities(func.count(BuyerStockInfo.id).label("total_item"),
                                                              func.sum(BuyerStockInfo.price).label(
                                                                  "total_buy_price")).filter(
        BuyerStockInfo.username == username).group_by(BuyerStockInfo.username).all()
    for i in with_buyer_stock_tab:
        result["total_item"] = i.total_item
        result["total_buy_price"] = round(i.total_buy_price, 2)
    current_price = StockInfo.quick_price.label("current_price")
    with_stock_tab = BuyerStockInfo.query.with_entities(BuyerStockInfo.id,
                                                        current_price) \
        .join(StockInfo, BuyerStockInfo.item_id == StockInfo.id).filter(BuyerStockInfo.username == username).all()
    for stock in with_stock_tab:
        result["total_current_price"] += float(stock.current_price)
    result["total_current_price"] = round(result["total_current_price"], 2)
    with_rent_tab = RentInfo.query.with_entities(func.sum(RentInfo.rent).label("total_rent")).filter(
        RentInfo.username == username).group_by(RentInfo.username).all()
    for i in with_rent_tab:
        result["total_rent"] = round(i.total_rent, 2)
    with_rent_period_tab = RentInfo.query.with_entities(RentInfo.rent, RentInfo.ctime).filter(
        and_(RentInfo.username == username, RentInfo.ctime >= get_0am_by_date(calendar_date(-30)))).all()
    for i in with_rent_period_tab:
        if i.ctime > get_0am_by_date(calendar_date(-7)):
            result["last_7d_rent"] += float(i.rent)
        if i.ctime > get_0am_by_date(calendar_date(-14)):
            result["last_14d_rent"] += float(i.rent)
        result["last_30d_rent"] += float(i.rent)
    result["last_7d_rent"] = "￥"+str(round(result["last_7d_rent"], 2))
    result["last_14d_rent"] = "￥"+str(round(result["last_14d_rent"], 2))
    result["last_30d_rent"] = "￥"+str(round(result["last_30d_rent"], 2))
    result["rent_interest"] = str(round((result["total_rent"] / result["total_buy_price"]) * 100, 2)) + "%"
    result["total_interest"] = str(round(((result["total_rent"] + result["total_current_price"] - result[
        "total_buy_price"]) / result["total_buy_price"]) * 100, 2)) + "%"
    result["total_rent"]="￥"+str(result["total_rent"])
    result["total_buy_price"] = "￥" + str(result["total_buy_price"])
    result["total_current_price"] = "￥" + str(result["total_current_price"])
    # print(result)
    return result



def UpdateCurrentPrice():
    logging.warning("[UpdateCurrentPrice] async updating")
    r = redis_con()
    stock_items = BuyerStockInfo.query.with_entities(distinct(BuyerStockInfo.item_id)).all()
    itemlist = []
    for item in stock_items:
        itemlist.append(list(item)[0])
    logging.warning("[UpdateCurrentPrice]  update item list %s"%(itemlist))
    if len(itemlist) > 0:
        count = get_current_price_by_items(itemlist)
        if count > 0:
            r.set("last_update", str(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))))

def get_last_update_time():
    r = redis_con()
    data = r.get("last_update")
    if data:
        return data


def set_buff_cookie(cookie):
    r = redis_con()
    r.set("item_price_cookie", cookie)

def upsert_proxy_token(token):
    r = redis_con()
    r.set("proxy_token", token)

def calendar_date(n=0):
    return str(time.strftime('%Y-%m-%d', time.localtime(time.time() + 86400 * n)))


def get_0am_by_date(s):
    timeArray = time.strptime(s, '%Y-%m-%d')
    ts = int(time.mktime(timeArray))
    return ts

def setHLval(r,itemid,price,sell_num):
    key = "full_price_%s" % (itemid)
    key2 = "sell_num_%s" % (itemid)
    date=calendar_date()

    hash_h=date+"_high"
    hval=r.hget(key,hash_h)
    if not hval:
        r.hset(key,hash_h,price)
        logging.warning("key not found, write new record: key: %s, hash: %s, val: %s"%(key,hash_h,price))
    elif float(hval)<price:
        r.hset(key,hash_h,price)
        logging.warning("existed price: %s, write new record: key: %s, hash: %s, val: %s"%(hval,key,hash_h,price))
    hash_l=date+"_low"
    lval=r.hget(key,hash_l)
    if not lval:
        r.hset(key,hash_l,price)
        logging.warning("key not found, write new record: key: %s, hash: %s, val: %s"%(key,hash_l,price))
    elif float(lval)>price:
        r.hset(key,hash_l,price)
        logging.warning("existed price: %s, write new record: key: %s, hash: %s, val: %s"%(lval,key,hash_l,price))

    hval_sell = r.hget(key2, hash_h)
    if not hval_sell:
        r.hset(key2, hash_h, sell_num)
        logging.warning("key not found, write new record: key: %s, hash: %s, val: %s" % (key2, hash_h, sell_num))
    elif float(hval_sell) < sell_num:
        r.hset(key2, hash_h, sell_num)
        logging.warning("existed count: %s, write new record: key: %s, hash: %s, val: %s" % (hval_sell, key2, hash_h, sell_num))
    lval_sell = r.hget(key2, hash_l)
    if not lval_sell:
        r.hset(key2, hash_l, sell_num)
        logging.warning("key not found, write new record: key: %s, hash: %s, val: %s" % (key2, hash_l, sell_num))
    elif float(lval_sell) > sell_num:
        r.hset(key2, hash_l, sell_num)
        logging.warning("existed count: %s, write new record: key: %s, hash: %s, val: %s" % (lval_sell, key2, hash_l, sell_num))


def get_current_price_by_items(stock_items=None,only_one=False):
    if stock_items is None:
        stock_items = []
    if not only_one:
        knife_list=[759509,776261,759326,42682,759460,776671,776583,759383,42349,42891,44002,775988,43052,773696,42530,42961,43162,42779,42461]
        stock_items+=knife_list
        stock_items=set(stock_items)
    count = 0
    r = redis_con()
    cookie = r.get("item_price_cookie")
    logging.warning("[get_current_price_by_items]  get price for item list %s" % (stock_items))
    for itemid in stock_items:
        url = "https://buff.163.com/api/market/goods/sell_order?game=csgo&goods_id=%s&page_num=1&sort_by=default&mode=&allow_tradable_cooldown=1" % (
            itemid)
        payload = {}
        time.sleep(2)
        headers = {
            'authority': 'buff.163.com',
            'accept': 'application/json, text/javascript, */*; q=0.01',
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36',
            'x-requested-with': 'XMLHttpRequest',
            'sec-fetch-site': 'same-origin',
            'sec-fetch-mode': 'cors',
            'sec-fetch-dest': 'empty',
            'referer': 'https://buff.163.com/goods/871535',
            'accept-language': 'zh-CN,zh;q=0.9',
            'Cookie': cookie.encode("utf-8").decode("latin1")
        }
        response = requests.request("GET", url, headers=headers, data=payload)
        # print(response.text)
        try:
            rejson = response.json()
            min_price = rejson["data"]["items"][0]["price"]
            sell_num = rejson["data"]["total_count"]
            key = "price_%s#:#%s" % (itemid, calendar_date())
            r.set(key, min_price)
            r.expire(key, 30 * 86400)
            setHLval(r,itemid,min_price,sell_num)
            logging.warning("Get Price for item: %s, resp: %s, set redis key: %s, value: %s"%(itemid,rejson,key,min_price))
            StockInfo.query.filter(StockInfo.id == itemid).update({StockInfo.quick_price: min_price})
            count += 1
        except:
            logging.warning("Get Price for item Fail: %s, req: %s, resp: %s"%(itemid,url,response.text))
            continue
    db.session.commit()
    db.session.close()
    return count


def GetTotalStock():
    keywords = ["%M4A4%", "%★%", "%M4A1%", "%AK-47%", "%AWP%", "%USP%", "%手套%", "%刀%", "%沙漠%"]
    rule = or_(*[StockInfo.name.like(w) for w in keywords])
    result = StockInfo.query.filter(rule).all()
    result_list = []
    for item in result:
        d = {
            "id": str(item.id),
            "name": str(item.name)
        }
        result_list.append(d)
    return result_list


def GetBuyerStockWithRent(username):
    # UpdateCurrentPrice()
    BuyerStock = GetBuyerStock(username)
    BuyerRent = GetBuyerRent(username)
    mtime = get_last_update_time()
    # rent_per_month={}
    for stock in BuyerStock:
        split_rent = []
        split_rent_str = []
        for rent_record in BuyerRent:
            if stock["stock_id"] == rent_record["stock_id"]:
                split_rent.append(float(rent_record["rent"]))
                split_rent_str.append(rent_record["rent"])
                # ts=rent_record["ctime"]
                # ts_local=time.localtime(ts)
                # date_month=time.strftime("%Y%m", ts_local)
                # if date_month not in rent_per_month.keys():
                #     rent_per_month[date_month]=0
                # rent_per_month[date_month]+=float(rent_record["rent"])
        stock["split_rent"] = "+".join(split_rent_str)
        stock["sum_rent"] = round(sum(split_rent), 2)
        stock["rent_interest"] = round(stock["sum_rent"] * 100 / float(stock["buy_price"]), 2)
        stock["rent_interest_all"] = round(
            (stock["sum_rent"] + float(stock["current_price"]) - float(stock["buy_price"])) * 100 / float(
                stock["buy_price"]),
            2)
        stock["price_mtime"] = mtime
        # stock["rent_per_month"]=rent_per_month
    return BuyerStock


def GetBuyerStock(username):
    r = redis_con()
    item_name = StockInfo.name.label("item_name")
    buy_price = BuyerStockInfo.price.label("buy_price")
    current_price = StockInfo.quick_price.label("current_price")
    with_name_tab = BuyerStockInfo.query.with_entities(BuyerStockInfo.id, BuyerStockInfo.item_id, item_name, buy_price,
                                                       current_price) \
        .join(StockInfo, BuyerStockInfo.item_id == StockInfo.id).filter(BuyerStockInfo.username == username)\
        .order_by(BuyerStockInfo.item_id.asc())\
        .all()
        # order_by(BuyerStockInfo.id.asc())\
    returnlist = []
    for i in with_name_tab:
        diff = 0
        key = "price_%s#:#%s" % (i.item_id, calendar_date(-1))
        try:
            last_day_price = float(r.get(key))
            if last_day_price:
                diff = round(float(i.current_price) - last_day_price, 2)
                if diff > 0:
                    diff = "+" + str(diff)
            else:
                logging.warning("no last day price: %s" % key)
        except:
            pass
            # logging.warning("get last day price error: %s" % key)
        k = {
            "stock_id": i.id,
            "item_id": i.item_id,
            "item_name": i.item_name,
            "buy_price": i.buy_price,
            "current_price": i.current_price,
            "price_diff_from_last_date": str(diff)
        }
        returnlist.append(k)
    logging.warning("GetBuyerStock: %s" % (json.dumps(returnlist)))
    return returnlist


def GetBuyerRent(username):
    with_rent_tab = RentInfo.query.with_entities(RentInfo.stock_id, RentInfo.item_id, RentInfo.rent, RentInfo.ctime).filter(
        RentInfo.username == username).all()
    returnlist = []
    for i in with_rent_tab:
        k = {
            "stock_id": i.stock_id,
            "item_id": i.item_id,
            "rent": i.rent,
            "ctime":i.ctime
        }
        returnlist.append(k)
    logging.warning("GetBuyerRent: %s" % (json.dumps(returnlist)))
    return returnlist


def GetBuyerRentGrpByMonth(username):
    with_rent_month_tab = RentInfo.query.with_entities(func.sum(RentInfo.rent).label("total_rent"),
                                                 func.from_unixtime((RentInfo.ctime), "%Y-%m").label("date")).filter(
        RentInfo.username == username).group_by(func.from_unixtime((RentInfo.ctime), "%Y-%m")).order_by("date").all()
    with_buyer_stock_tab = BuyerStockInfo.query.with_entities(func.sum(BuyerStockInfo.price).label(
                                                                  "total_buy_price")).filter(
        BuyerStockInfo.username == username).group_by(BuyerStockInfo.username).all()
    total_buy_price = round(with_buyer_stock_tab[0].total_buy_price, 2)
    rentByMonth = {}
    for i in with_rent_month_tab:
        if i.date not in rentByMonth.keys():
            rentByMonth[str(i.date)]=0
        rentByMonth[str(i.date)]+=round(float(i.total_rent),2)
    return rentByMonth,total_buy_price


def GetBuyerRentGrpByDateNd(username,n):
    with_rent_tab = RentInfo.query.with_entities(func.sum(RentInfo.rent).label("total_rent"),
                                                 func.from_unixtime((RentInfo.ctime), "%Y-%m-%d").label("date")).filter(
        RentInfo.username == username).group_by(func.from_unixtime((RentInfo.ctime), "%Y-%m-%d")).all()
    rentByDate = {"rent_by_date": [], "date": []}
    for i in with_rent_tab:
        rentByDate["rent_by_date"].append(round(i.total_rent, 2))
        rentByDate["date"].append(i.date)
    logging.warning("rent by date: %s, date: %s"%(rentByDate["rent_by_date"],rentByDate["date"]))
    # if len(rentByDate["date"]) > n:
    rentByDate["rent_by_date"] = rentByDate["rent_by_date"][-1*n:]
    rentByDate["date"] = rentByDate["date"][-1*n:]
    try:
        avg_rent = round(sum(rentByDate["rent_by_date"]) / len(rentByDate["rent_by_date"]), 2)
    except ZeroDivisionError:
        avg_rent = 0
    rentByDate["avg_day"] = [avg_rent for i in range(len(rentByDate["rent_by_date"]))]
    return rentByDate


def addRentForItem(username, stock_id, item_id, rents):
    t = int(time.time())
    if len(rents) > 0:
        rent_list = rents.split(",")
        for rent in rent_list:
            try:
                if isinstance(float(rent), float):
                    rent_info = RentInfo(stock_id=stock_id, username=username, item_id=item_id, rent=rent, ctime=t,
                                         mtime=t)
                    db.session.add(rent_info)
                    db.session.commit()
                    db.session.close()
            except:
                continue


def deleteRentForItem(stock_id):
    rent_info = RentInfo.query.filter(RentInfo.stock_id == stock_id).order_by(
        text('id desc')).limit(1).first()
    db.session.delete(rent_info)
    db.session.commit()
    db.session.close()


def deleteAllForItem(stock_id):
    RentInfo.query.filter(RentInfo.stock_id == stock_id).delete()
    buyerstock_info = BuyerStockInfo.query.filter(BuyerStockInfo.id == stock_id).first()
    db.session.delete(buyerstock_info)
    db.session.commit()
    db.session.close()


def InsertDataInfoBuyerStock(data):
    pass

def addNewSkin(id,name,price):
    t = int(time.time())
    try:
        name=name.strip()
        stock_info = StockInfo(id=id, name=name, quick_price=price,mtime=t)
        db.session.add(stock_info)
        db.session.commit()
        db.session.close()
        logging.warning("New Skin Updated. id=%s, name=\"%s\", price=%s"%(id,name,price))
    except:
        logging.warning("New Skin not Updated. id=%s, name=\"%s\", price=%s"%(id,name,price))
        pass
if __name__ == '__main__':
    # get_current_price_by_items(["33887"])
    # get_0am_by_date("2022-02-23")
    UpdateCurrentPrice()
